package init;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

import algo.Friis;

import objects.AccessPoint;
import objects.Measurement;
import objects.Point;
import objects.ReferencePoint;

import dao.AccessPointsDAO;
import dao.ReferencePointsDAO;
import divTools.CheckMAC;
import divTools.Converter;

public class InitMeasurements {

	private static HashMap<String, AccessPoint> accessPoints;
	
	/**
	 * Imports the reference points and the measurements from a file
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public static int addMeasurements(String path) throws IOException {
		
		int nbMeasurements = 0;
		int nbRefPoints = 0;
		ArrayList<ReferencePoint> refPoints = new ArrayList<ReferencePoint>();
		HashMap<String, ArrayList<Integer>> allMeasurements = new HashMap<String, ArrayList<Integer>>();
		
		try
	    {
	       BufferedReader buffer = new BufferedReader(new FileReader(path));
	       String line;	       

	       while((line = buffer.readLine())!= null)
	       {
	    	   if (!line.startsWith("#") && !line.isEmpty()) {
	    		   String[] splittedLine = line.split(";");
	    		   
	    		   ReferencePoint newRefPoint = new ReferencePoint(); 	    		   
	    		   
	    		   try {
	    			   Point newPoint = new Point(Float.parseFloat(splittedLine[0]), Float.parseFloat(splittedLine[1]), Float.parseFloat(splittedLine[2]));
	    			   
	    			   if (refPoints.size() != 0 && newPoint.equals(refPoints.get(nbRefPoints - 1).getCoordinates())) {
	    				   extractMeasurements(splittedLine, allMeasurements);
	    			   }
	    			   else {
	    				   if(refPoints.size() != 0) {
	    					   computesAveragesAndFriisIndexes(allMeasurements, refPoints.get(nbRefPoints - 1));
	    					   allMeasurements = new HashMap<String, ArrayList<Integer>>();
	    				   }
	    				   newRefPoint.setCoordinates(newPoint);
	    				   extractMeasurements(splittedLine, allMeasurements);
		    			   refPoints.add(newRefPoint);
		    			   nbRefPoints++;
	    			   }
	    			  
	    		   }
	    		   catch (NumberFormatException e)
	    		   {
	    			   continue;
	    		   }
	    	   }
	       }
	       buffer.close();
	       
	       computesAveragesAndFriisIndexes(allMeasurements, refPoints.get(nbRefPoints - 1));
	       
	       nbMeasurements += ReferencePointsDAO.create(refPoints, getAccessPoints());
	    }
	    catch (FileNotFoundException e)
	    {
	       System.out.println("Le fichier est introuvable !");
	    }
	    
	    return nbMeasurements;
	}

	private static void extractMeasurements(String[] splittedLine, HashMap<String, ArrayList<Integer>> allMeasurements) {
		
		// contains all the measurements : key = mac address, value = array of power values
		
		for (int i = 4 ; i < splittedLine.length ; i = i + 2) {
			
			if (!CheckMAC.IsMAC(splittedLine[i])) 
				continue;
			String macAdress = splittedLine[i].toUpperCase();			
			int powerValue;
			
			try {
				powerValue = Integer.parseInt(splittedLine[i+1]);
			}
			catch (NumberFormatException e) {
				continue;
			}
			
			if (!allMeasurements.containsKey(macAdress)) {
				ArrayList<Integer> values = new ArrayList<Integer>();
				values.add(powerValue);
				allMeasurements.put(macAdress, values);
			}
			else {
				ArrayList<Integer> values = allMeasurements.get(macAdress);
				values.add(powerValue);
				allMeasurements.put(macAdress, values);
			}
		}
	}

	private static void computesAveragesAndFriisIndexes(
			HashMap<String, ArrayList<Integer>> allMeasurements, ReferencePoint refPoint) {
		
		// the final map containing a measurement for each AP capted
		refPoint.setMeasurements(new HashMap<String, Measurement>());
		
		Set<Entry<String, ArrayList<Integer>>> entries = allMeasurements.entrySet();
	    Iterator<Entry<String, ArrayList<Integer>>> it = entries.iterator();
	    
	    while (it.hasNext()) {
			
	    	Entry<String, ArrayList<Integer>> entry = (Entry<String, ArrayList<Integer>>) it.next();
	    	ArrayList<Integer> values = entry.getValue();
	    	Measurement measurement = new Measurement();
	    	measurement.setMacAdress(entry.getKey());
	    	float sumPowerValues = 0;
	    	
	    	// computation of the average power
	    	for (Integer value : values) {
	    		sumPowerValues += Converter.dBmToMw(value);
	    	}
	    	measurement.setPowerValue(Converter.MwTodBm(sumPowerValues / values.size()));
	    	refPoint.getMeasurements().put(entry.getKey(), measurement);
	    	
	    	// computation of the friis index
	    	if (getAccessPoints().containsKey(measurement.getMacAdress())) {
	    		float friisIndex = Friis.computeFriisIndex(getAccessPoints().get(measurement.getMacAdress()), refPoint);
	    		measurement.setFriisIndex(friisIndex);
	    	}
	    	else {
	    		continue;
	    	}
	    	
	    	refPoint.getMeasurements().put(entry.getKey(), measurement);
	    }
	}

	public static HashMap<String, AccessPoint> getAccessPoints() {
		
		if (accessPoints == null)
			accessPoints = AccessPointsDAO.read();
		return accessPoints;
	}
}
